package main.model.parser;

import java.text.ParseException;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;


/**
 * A interface that is used so that Visitor pattern can be implemented.
 *
 * TODO (kevin): Switch from specifically "Row"s to using an Abstract Data Type.
 *
 * @author Kevin Gao,
 *
 */
public abstract class ParseStrategy {

    private final Set<String> myHeaders;

    /**
     * Default constructor.
     */
    public ParseStrategy () {
        // Must be linked hash set to maintain order of headers
        myHeaders = new LinkedHashSet<String>();
    }

    /**
     * Determines whether the current builder understands the filetype.
     *
     * @param filetype filetype as a string
     * @return
     */
    public abstract boolean canRead (String filetype);

    /**
     * Visit this strategy and parse some <del>abstract data type,</del> row.
     *
     * @param line line to parse
     * @return Map of string -> object since we're only dealing w/ rows for now
     * @throws ParseException due to parsing
     */
    public abstract Map<String, Object> parseLineToRow (String line) throws ParseException;

    /**
     * Parses headers and sets current headers to it.
     *
     * @param line headers to parse
     */
    public abstract void setHeaders (String line);

    /**
     * Adds a header.
     *
     * @param h header to add
     */
    public void addHeader (String h) {
        if (myHeaders.contains(h)) {
            System.err.println("Detected duplicate header: " + h);
        }
        myHeaders.add(h);
    }

    /**
     * Returns if a string is in the current set of headers
     *
     * @param h string to verify
     * @return
     */
    public boolean isHeader (String h) {
        return myHeaders.contains(h);
    }

    /**
     * Returns the header at the index.
     *
     * @param idx index requested
     * @return
     */
    public String getHeaderAt (int idx) {
        Iterator<String> iter = myHeaders.iterator();
        for (int i = 0; i < idx && iter.hasNext(); i++) {
            iter.next();
        }
        return iter.next();
    }

    /**
     * Returns the number of headers.
     *
     * @return
     */
    public int getNumHeaders () {
        return myHeaders.size();
    }

    /**
     * Resets the headers
     */
    public void clearHeaders () {
        if (myHeaders != null) {
            myHeaders.clear();
        }
    }

}
